<?php
//-------------------------------------------------------------------------
// OVIDENTIA http://www.ovidentia.org
// Ovidentia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//-------------------------------------------------------------------------
/**
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 * @copyright Copyright (c) 2006 by CANTICO ({@link http://www.cantico.fr})
 */
include_once 'base.php';
require_once $GLOBALS['babInstallPath'] . 'addons/widgets/widgets/containerwidget.class.php';



/**
 * Checks whether a form with the specified unique id $formUid has
 * already been treated.
 * The specified unique id is then marked as treated.
 *
 * @param string	$formUid	A form unique id.
 * @return bool					true if the form has already been treated, false otherwise.
 */
function Widget_checkFormAlreadySubmitted($formUid)
{
	if (!isset($_SESSION['Widget_form_uid_' . $formUid])) {
		$_SESSION['Widget_form_uid_' . $formUid] = true;
		return false;
	}
	return true;
}




/**
 * Constructs a Widget_Form.
 *
 * @param Widget_Layout	$layout		The layout that will manage how widgets are displayed in this container.
 * @param string		$id			The item unique id.
 * @return Widget_Form
 */
function Widget_Form($id = null, Widget_Layout $layout = null)
{
	return new Widget_Form($id, $layout);
}



/**
 * A Widget_Form.
 *
 */
class Widget_Form extends Widget_ContainerWidget implements Widget_Displayable_Interface
{
	/**
	 * An array of name => value pairs.
	 *
	 * @var $_hiddenFields	array
	 */
	private $_hiddenFields;
	private $_selfPageHiddenFields = false;

	private $_readonly = false;
	private $_fields = array();
	private $_fieldsvalues = array();

	/**
	 * @var bool
	 */
	private $checkUnsaved = false;
	/**
	 * @var string
	 */
	private $unsavedMessage = '';

	/**
	 * @var bool
	 */
	private $_colon = false;


	/**
	 * @var string
	 */
	private $anchorname = null;


	/**
	 * @param Widget_Layout $layout	The layout that will manage how widgets are displayed in this container.
	 * @param string $id			The item unique id.
	 * @return Widget_Form
	 */
	public function __construct($id = null, Widget_Layout $layout = null)
	{
		if (null === $layout) {
			require_once FUNC_WIDGETS_PHP_PATH . 'vboxlayout.class.php';
			$layout = new Widget_VBoxLayout();
		}


		parent::__construct($id, $layout);
		$this->_hiddenFields = array();
	}

	/**
	 * Set the form as readonly, no modifications on server with this form
	 * @return Widget_Form
	 */
	public function setReadOnly($flag = true) {
		$this->_readonly = $flag;

		return $this;
	}

	/**
	 * @return boolean
	 */
	public function getReadOnly() {
		return $this->_readonly;
	}

	/**
	 * Add colon caracters after labels in forms
	 * @param bool $colon		default true
	 * @return Widget_Form
	 */
	public function colon($colon = true) {
		$this->_colon = $colon;
		return $this;
	}

	/**
	 * @see Widget_Label::isColon()
	 * @return bool
	 */
	public function isColon() {
		return $this->_colon;
	}



	/**
	 * Adds a parameter that will be submitted with the form.
	 * If the parameter exists already, it is replaced
	 *
	 * @param string $name
	 * @param string $value
	 */
	public function setHiddenValue($name, $value)
	{
//		assert('is_string($name); /* The "name" parameter must be a string. */');
//		assert('is_string($value); /* The "value" parameter must be a string. */');
		$this->_hiddenFields[$name] = $value;

		return $this;
	}

	/**
	 * Return the value of a parameter (hidden field)
	 *
	 * @param string $name name of the hidden field
	 *
	 * @return string, null
	 */
	public function getHiddenValue($name)
	{
		assert('is_string($name); /* The "name" parameter must be a string. */');
		if (isset($this->_hiddenFields[$name])) {
			return $this->_hiddenFields[$name];
		} else {
			return null;
		}
	}

	/**
	 * Return hidden fields
	 *
	 * @return array
	 */
	public function getHiddenFields() {
		return $this->_hiddenFields;
	}



	/**
	 * Adds parameters that will be submitted with the form.
	 *
	 * This method is useful to transmit/retrieve quickly information stored in an array.
	 *
	 * @param string basename	The name that will be prepended to parameter names
	 * @param array $values		An associative, possibly nested, array of (name => value) pairs
	 */
	public function setHiddenValues($basename, $values)
	{
		assert('is_string($basename); /* The "basename" parameter must be a string. */');
		assert('is_array($values); /* The "values" parameter must be an array. */');
		foreach ($values as $name => $value) {
			if (!is_array($value)) {
				$this->setHiddenValue($basename . '[' . $name . ']', $value);
			} else {
				$this->setHiddenValues($basename . '[' . $name . ']', $value);
			}
		}

		return $this;
	}


	/**
	 * @return array
	 */
	public function getFields($parent = null) {
		if (null === $parent) {
			$parent = $this;
			$this->_fields = array();
		}

		if ($parent instanceOf Widget_ContainerWidget) {
			$layout = $parent->getLayout();
		} else {
			$layout = $parent;
		}


		if (NULL === $layout) {
			trigger_error('The layout of the containerWidget "'.get_class($parent).'" must not be null');
			die();
		}

		foreach($layout->getItems() as $item) {
			if ($item instanceOf Widget_InputWidget) {
				$this->_fields[] = $item;
			} elseif ($item instanceOf Widget_ContainerWidget || $item instanceOf Widget_Layout) {
				$this->_fields += $this->getFields($item);
			}
		}


		return $this->_fields;
	}


	/**
	 * get a field value
	 * @param	array	$namePath
	 * @return 	mixed
	 */
	public function getValue($namePath) {

		assert('is_array($namePath); /* The "namePath" parameter to getValue() method must be an array. */');
		assert('!empty($namePath); /* The "namePath" parameter to getValue() method must not be empty. */');

		$tmp = $this->_fieldsvalues;
		foreach($namePath as $key) {

			if (!isset($tmp[$key])) {
				return null;
			}

			$tmp = $tmp[$key];
		}
		return $tmp;
	}


	/**
	 * @param	array|string	$namePath
	 * @param	mixed			$value
	 * @return 	Widget_Form
	 */
	public function setValue($namePath, $value) {

		if (is_string($namePath)) {
			$namePath = explode('/', $namePath);
		}
		$tmp = &$this->_fieldsvalues;
		foreach($namePath as $key) {

			if (!isset($tmp[$key])) {
				$tmp[$key] = array();
			}
			$tmp = &$tmp[$key];
		}

		$tmp = $value;

		return $this;
	}



	/**
	 * @param	array	$row
	 * @param	array 	$namePathBase
	 * @return 	Widget_Form
	 */
	public function setValues($row, $namePathBase = array()) {
		foreach($row as $namePath => $value) {
			$tmp = $namePathBase;
			$tmp[] = $namePath;
			if (is_array($value)) {
				$this->setValues($value, $tmp);
			} else {
				$this->setValue($tmp, $value);
			}
		}

		return $this;
	}

	/**
	 * Get values
	 * @since 0.1.3
	 * @return array
	 */
	public function getValues() {

		return $this->_fieldsvalues;

	}

	/**
	 * Set anchor in destination page
	 * @param	string	$anchorname
	 * @return Widget_Form
	 */
	public function setAnchor($anchorname) {
		$this->anchorname = $anchorname;
	}


	/**
	 * create necessary hidden fields to post on same page
	 * @return 	Widget_Form
	 */
	public function setSelfPageHiddenFields($status = true) {
		$this->_selfPageHiddenFields = $status;
		return $this;
	}


	/**
	 * Test mandatory fields
	 * Return false if one mandatory field is empty
	 *
	 * @throw Widget_InputMandatoryException
	 *
	 * @return bool
	 */
	public function testMandatory()
	{
		/* @var $field Widget_InputWidget */
		foreach($this->getFields() as $field) {

			if (false === $field->testMandatory()) {
				return false;
			}
		}

		return true;
	}



	/**
	 * Activates/deactivates a popup confirmation message displayed if the user tries to 'unload'
	 * the current page (close the page, follow a link...) while there are unsaved changes on the form.
	 *
	 * @param bool		$check				True to activate unsaved form checking, false to deactivate.
	 * @param string	$unsavedMessage		The message that will be displayed in the confirmation popup.
	 */
	public function checkUnsaved($check, $unsavedMessage)
	{
		$this->checkUnsaved = $check;
		$this->unsavedMessage = $unsavedMessage;
		return $this;
	}

	/**
	 * The item classes.
	 *
	 * @return array
	 */
	public function getClasses()
	{
		$classes = parent::getClasses();
		$classes[] = 'widget-form';
		return $classes;
	}


	public function display(Widget_Canvas $canvas)
	{
		if ($this->checkUnsaved) {
			$this->setMetadata('checkUnsaved', true);
			$this->setMetadata('unsavedMessage', $this->unsavedMessage);
		}
		return $canvas->form(
			 $this->getId(),
			 $this->getClasses(),
			 $this->_readonly,
			 $this->_hiddenFields,
			 array($this->getLayout()),
			 $this->_selfPageHiddenFields,
			 $this->anchorname,
			 $this->getTitle()
		) . $canvas->metadata($this->getId(), $this->getMetadata());;
	}

}


